#include "Binding.h"

#include <vector>
#include <unordered_map>
#include <utility>
#include <fstream>
#include <iostream>
#include <string>


// 辅助函数：生成一段二阶 B 样条曲线
std::vector<std::pair<double, double>> generateBSpline(
    const std::pair<double, double>& p0,
    const std::pair<double, double>& p1,
    const std::pair<double, double>& p2,
    int segments
) {
    std::vector<std::pair<double, double>> result;
    for (int i = 0; i <= segments; ++i) {
        double t = static_cast<double>(i) / segments;
        double b0 = (1 - t) * (1 - t);
        double b1 = 2 * (1 - t) * t;
        double b2 = t * t;
        double x = b0 * p0.first + b1 * p1.first + b2 * p2.first;
        double y = b0 * p0.second + b1 * p1.second + b2 * p2.second;
        result.emplace_back(x, y);
    }
    return result;
}

// 主函数：对每条绑定边生成变形曲线
std::vector<std::vector<std::pair<double, double>>> warpEdges(
    const std::vector<BindingInfo>& bindings,
    const std::vector<Node>& nodes,
    int segments,
    double alpha
) {
    std::unordered_map<int, Node> nodeMap;
    for (const auto& node : nodes) {
        nodeMap[node.id] = node;
    }

    std::vector<std::vector<std::pair<double, double>>> warpedEdges;

    for (const auto& binding : bindings) {
        const auto& fromNode = nodeMap[binding.edge.from];
        const auto& toNode = nodeMap[binding.edge.to];

        std::pair<double, double> p0 = { fromNode.lon, fromNode.lat };
        std::pair<double, double> p2 = { toNode.lon, toNode.lat };

        std::pair<double, double> midpoint = {
            (p0.first + p2.first) / 2.0,
            (p0.second + p2.second) / 2.0
        };

        std::pair<double, double> control = {
            midpoint.first * (1.0 - alpha) + binding.nearest.first * alpha,
            midpoint.second * (1.0 - alpha) + binding.nearest.second * alpha
        };

        warpedEdges.push_back(generateBSpline(p0, control, p2, segments));
    }

    return warpedEdges;
}



void writeWarpedEdgesToCsv(
    const std::vector<std::vector<std::pair<double, double>>>& warpedEdges,
    const std::vector<BindingInfo>& bindings,
    const std::string& filename
) {
    if (warpedEdges.size() != bindings.size()) {
        std::cerr << "Size mismatch between warpedEdges and bindings!" << std::endl;
        return;
    }

    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cerr << "Failed to open file for writing: " << filename << std::endl;
        return;
    }

    file << "edge_id,point_index,lon,lat,cluster\n";

    for (size_t edgeId = 0; edgeId < warpedEdges.size(); ++edgeId) {
        const auto& points = warpedEdges[edgeId];
        int clusterId = bindings[edgeId].clusterId;

        for (size_t i = 0; i < points.size(); ++i) {
            file << edgeId << "," << i << ","
                 << points[i].first << "," << points[i].second << ","
                 << clusterId << "\n";
        }
    }

    file.close();
    std::cout << "Warped edges written to: " << filename << std::endl;
}